package com.oj.controller;

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.oj.entity.*;
import com.oj.mapper.AttendMapper;
import com.oj.mapper.ContestMapper;
import com.oj.mapper.ProblemMapper;
import com.oj.mapper.ContestProblemMapper;
import com.oj.service.ContestService;
import com.oj.service.PrivilegeService;
import com.oj.service.UserService;
import com.oj.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Controller
@RequestMapping
public class ContestController {
    @Autowired
    private ContestService contestService;

    @Autowired
    private ContestMapper contestMapper;

    @Autowired
    private AttendMapper attendMapper;

    @Autowired
    private UserService userService;

    @Autowired
    private ContestProblemMapper contestProblemMapper;

    @Autowired
    private PrivilegeService privilegeService;

    @RequestMapping(value = {"/admin/contest/new"}, method = RequestMethod.GET)
    public ModelAndView newContest(Model model){
        try {
            Contest contest = new Contest();
            if (contest == null) {
                return null;
            }
            ModelAndView mv=new ModelAndView();
            mv.addObject("contest", contest);
            mv.setViewName("admin/contest-edit.html");
            return mv;
        }catch (Exception e) {
        }
        return null;
    }

    @GetMapping(value = {"/admin/contest/edit/{contestId}"})
    public ModelAndView edit(@PathVariable(value = "contestId",required = false)Integer contestId,
                             HttpServletRequest request){
        try {
            Contest contest = contestMapper.queryAdmin(contestId);
            if (contest == null) {
                return null;
            }

            ModelAndView mv=new ModelAndView();
            mv.addObject("contest", contest);
            mv.setViewName("admin/contest-edit.html");
            return mv;
        }catch (Exception e) {
        }
        return null;
    }

    @GetMapping(value = {"/admin/contest/delete/{contestId}"})
    public String delete(@PathVariable(value = "contestId",required = false)Integer contestId,
                             HttpServletRequest request){
        try {
            Contest contest = contestMapper.queryAdmin(contestId);
            if (contest == null) {
                return null;
            }
            contest.setDefunct("Y");
            if (contestMapper.update(contest)) {
                log.info("contest " + contestId + " delete.");
            }
            return "redirect:/contests";
        }catch (Exception e) {
        }
        return "redirect:/contests";
    }
    @GetMapping(value = {"/admin/contest/resume/{contestId}"})
    public String resume(@PathVariable(value = "contestId",required = false)Integer contestId,
                             HttpServletRequest request){
        try {
            Contest contest = contestMapper.queryAdmin(contestId);
            if (contest == null) {
                return null;
            }
            contest.setDefunct("N");
            if (contestMapper.update(contest)) {
                log.info("contest " + contestId + " resume.");
            }

            return "redirect:/contests";
        }catch (Exception e) {
        }
        return "redirect:/contests";
    }

    @ResponseBody
    @PostMapping(value = "/api/admin/contest/post")
    public Result postContest(@RequestBody @Validated(value = {Contest.updateValid.class}) Contest contest,
                              HttpServletRequest request, HttpServletResponse response, Model model){
        log.info(contest.toString());
        if (contest.getContest_id() == 0) {
            return newContest(contest, request);
        } else {
            return editContest(contest, request);
        }
    }
    public Result newContest(Contest contest, HttpServletRequest request) {
        try {
            Date dt = new Date();
            SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            contest.setCreate_time(Timestamp.valueOf(simpleDate.format(dt)));
            contest.setCreate_user(request.getSession().getAttribute("session_username").toString());

            if (contestMapper.insert(contest)) {
                return Result.success();
            }
            log.error("contest insert failed.");
        } catch (Exception e) {
            log.error("newContest Exception."+ e.getMessage());
        }
        return Result.error(CodeMsg.INNER_FAULT.locale());
    }
    public Result editContest(Contest contest, HttpServletRequest request) {
        try {
            if (contestMapper.queryAdmin(contest.getContest_id()) == null) {
                return Result.error(CodeMsg.PARAM_INVALID.locale());
            }

            if (contestMapper.update(contest)) {
                return Result.success();
            }
            log.error("contest update failed.");
        } catch (Exception e) {
            log.error("edit contest Exception."+ e.getMessage());
        }
        return Result.error(CodeMsg.INNER_FAULT.locale());
    }

    public Contest getContestByReqMap(Map<String, Object> map) {
        if (map.get("title") == null) {
            return null;
        }

        Contest contest = new Contest();
        contest.setTitle(map.get("title").toString());

        if (map.get("desc") != null) {
            contest.setDescription(map.get("desc").toString());
        }

        return contest;
    }

    @RequestMapping(value = {"/contests",
            "/contests/page/{pageNum}"}, method = RequestMethod.GET)
    public ModelAndView contests(@PathVariable(value = "pageNum",required = false)Integer pageNum,
                                 @RequestParam(value = "pageSize",required = false, defaultValue = "50")Integer pageSize,
                                 HttpServletRequest request){
        if (pageNum == null) {
            pageNum = 1;
        }
        PageHelper.startPage(1,100);
        Map param = new HashMap();
        param.put("unfinished", 1);

        User user_ = userService.getUserBySession(request);
        if (user_ == null || !privilegeService.admin(user_.getUsername())) {
            param.put("defunct", 'N');
        }

        Page<Contest> contestsUnFinish = contestMapper.findByPaging(param);
        for (Contest c: contestsUnFinish) {
            Map param1 = new HashMap();
            param1.put("contestId", c.getContest_id());
            List<Attend> attendList = attendMapper.queryList(param1);
            c.setRegistrants(attendList.size());
            c.setDuring(DateUtil.minuteToString((c.getEnd_time().getTime()-c.getStart_time().getTime())/1000/60));

            Date dt = new Date();
            if (c.getStart_time().getTime()>dt.getTime()) {
                c.setStatus("PENDING");
                c.setLeftTime(DateUtil.secondToString((c.getStart_time().getTime()-new Date().getTime())/1000));
                c.setFriendlyLeftTime(DateUtil.getFriendlyTimeLeft((c.getStart_time().getTime()- new Date().getTime())/1000));
            } else if (c.getEnd_time().getTime()>dt.getTime()) {
                c.setStatus("RUNNING");
                c.setLeftTime(DateUtil.secondToString((c.getEnd_time().getTime()-new Date().getTime())/1000));
                c.setFriendlyLeftTime(DateUtil.getFriendlyTimeLeft((c.getEnd_time().getTime()-new Date().getTime())/1000));
            } else {
                c.setStatus("ENDED");
                c.setLeftTime("00:00:00");
                c.setFriendlyLeftTime("00:00:00");
            }

            if (c.getStart_reg().getTime()>dt.getTime()) {
                c.setRegStatus("PENDING");
                c.setRegleftTime(DateUtil.secondToString((c.getStart_reg().getTime()-new Date().getTime())/1000));
                c.setFriendlyRegleftTime(DateUtil.getFriendlyTimeLeft((c.getStart_reg().getTime()-new Date().getTime())/1000));
            } else if (c.getEnd_reg().getTime()>dt.getTime()) {
                c.setRegStatus("RUNNING");
                c.setRegleftTime(DateUtil.secondToString((c.getEnd_reg().getTime()-new Date().getTime())/1000));
                c.setFriendlyRegleftTime(DateUtil.getFriendlyTimeLeft((c.getEnd_reg().getTime()-new Date().getTime())/1000));
            } else {
                c.setRegStatus("ENDED");
                c.setRegleftTime("00:00:00");
                c.setFriendlyRegleftTime("00:00:00");
            }

            if (request.getSession().getAttribute("session_username") != null) {
                String username = request.getSession().getAttribute("session_username").toString();
                if (username != null) {
                    User user = userService.query(username);
                    if (user != null) {
                        if (attendMapper.query(c.getContest_id(), username) != null) {
                            c.setIsRegister("Y");
                        }else{
                            c.setIsRegister("N");
                        }
                    }
                }
            }
        }

        PageHelper.startPage(pageNum,pageSize);
        Map param1 = new HashMap();
        param1.put("finished", 1);
        if (user_ == null || !privilegeService.admin(user_.getUsername())) {
            param1.put("defunct", 'N');
        }
        Page<Contest> contests_ = contestMapper.findByPaging(param1);
        for (Contest contest: contests_) {
            Map param2 = new HashMap();
            param2.put("contestId", contest.getContest_id());
            contest.setAttendList(attendMapper.queryList(param2));
            contest.setDuring(DateUtil.minuteToString((contest.getEnd_time().getTime()-contest.getStart_time().getTime())/1000/60));
        }

        PageInfo<Contest> pageInfoUnFinish = new PageInfo<>(contestsUnFinish);
        PageInfo<Contest> pageInfo = new PageInfo<>(contests_);
        ModelAndView mv = new ModelAndView();
        mv.addObject("unfinshContest", pageInfoUnFinish);
        mv.addObject("pageInfo", pageInfo);
        mv.setViewName("contest/contests.html");
        return mv;
    }

    @GetMapping("/contest/{contestId}")
    public ModelAndView contest(@PathVariable String contestId, HttpServletRequest request){
        Contest contest;
        User u = userService.getUserBySession(request);
        if (u == null || !privilegeService.admin(u.getUsername())) {
            contest = contestService.query(Integer.parseInt(contestId));
        } else {
            contest = contestMapper.queryAdmin(Integer.parseInt(contestId));
        }
        if (contest == null) {
            return null;
        }

        Date dt = new Date();
        if (contest.getStart_time().getTime()>dt.getTime()) {
            contest.setStatus("PENDING");
            contest.setLeftTime(DateUtil.secondToString((contest.getStart_time().getTime()-new Date().getTime())/1000));
            contest.setFriendlyLeftTime(DateUtil.getFriendlyTimeLeft((contest.getStart_time().getTime()- new Date().getTime())/1000));
        } else if (contest.getEnd_time().getTime()>dt.getTime()) {
            contest.setStatus("RUNNING");
            contest.setLeftTime(DateUtil.secondToString((contest.getEnd_time().getTime()-new Date().getTime())/1000));
            contest.setFriendlyLeftTime(DateUtil.getFriendlyTimeLeft((contest.getEnd_time().getTime()-new Date().getTime())/1000));
        } else {
            contest.setStatus("ENDED");
            contest.setLeftTime("00:00:00");
            contest.setFriendlyLeftTime("00:00:00");
        }

        List<ContestProblem> problems = contestProblemMapper.queryByContest(Integer.parseInt(contestId));

        int index = 0;
        String[] indexList={"A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"};
        for (int i = 0; i < 26; i++) {
            if (contestProblemMapper.query(Integer.parseInt(contestId), indexList[i]) == null) {
                index = i;
                break;
            }
        }

        ModelAndView mv = new ModelAndView();
        mv.addObject("contest", contest);
        mv.addObject("problems", problems);
        mv.addObject("idleNum", indexList[index]);
        mv.setViewName("contest/contest.html");
        return mv;
    }

    @ResponseBody
    @RequestMapping(value = {"/api/contest/query"}, method = RequestMethod.GET)
    public Result<List> apiContests(){
        return Result.success(contestService.query());
    }

    @ResponseBody
    @RequestMapping(value = {"/api/admin/contest/collect"}, method = RequestMethod.GET)
    public Result apiContestsCollect(){
        OJCollector.CollectContests();
        return Result.success();
    }

    @RequestMapping(value = {"/contests/events"}, method = RequestMethod.GET)
    public String contests_global(Model model){
        return "contest/contests-events";
    }
}